// **************************************************************
// COPYRIGHT(c)2020, Xidian University
// All rights reserved.
//
// IP LIB INDEX : 
// IP Name      : 
//                
// File name    :
// Module name  : 
// Full name    :
//
// Author       :  Hbing 
// Email        :  2629029232@qq.com
// Data         :  2020/8/24
// Version      :  V 1.0 
// 
//Abstract      :
// Called by    :  Father Module
// 
// Modification history
// ------------------------------------------------------------------------------------------------------
// 
// *********************************************************************
`include "top_define.v"
// *******************
// TIMESCALE
// ******************* 
`timescale 1ns/1ps 

// *******************
// DESCRIPTION
// *******************
// 针对40G交换单元实现4clk写一个最短帧入队结果sr_rx_fifo
// 为达到速率，所有FIFO使用首字置出--rx_fifo/sr_rx_fifo/free_BD_fifo
// 暂定队列总数为25--单播8*4+组播1（组播和广播放在一个队列，多播不设优先级？）
// --主要修改--
// 对于入队失败的数据帧（包含接收调度告知的入队失败，以及入队总调度判断的入队失败）以及捕获的数据帧都要写sr_rx_fifo--不必，只写入队成功
// 所有接到rx_fifo信息的数据帧都写一个入队结果FIFO(enqueue_result_fifo)，若结果为0，则在bus_master_rx模块拉高一个请求trans_start，但是不暂存数据
// 为了方便bus_master_rx对于所有的数据帧都发起一个使能，读取数据，为了提速，分组处理部分数据存在FIFO里
// --修改--
// 将状态机与BD申请分开，即使在BD申请过程中状态机也能运行到下一帧的BD申请前一个状态
//*******************
//DEFINE(s)
//*******************
//`define UDLY 1    //Unit delay, for non-blocking assignments in sequential logic

//*******************
//DEFINE MODULE PORT
module schedule_enqueue(
	//sysrem input/output
	input  wire 		clk  ,
	input  wire 		rst_n,
	//queue schedule init done
	output reg 			init_done,
	//with frame_process
	// output reg  [  4:0] out_buf_clr  ,  //入队失败，清空分组处理的缓存区
	//with rx_fifo
	/*(*mark_debug = "true"*)*/ input  wire 		rx_fifo_empty,
	/*(*mark_debug = "true"*)*/ output reg  		rx_fifo_rden ,
	/*(*mark_debug = "true"*)*/ input  wire [ 31:0] rx_fifo_rdata,
	//with sr_rx_fifo
	/*(*mark_debug = "true"*)*/ input  wire 		sr_rx_fifo_full ,  //将满标志--预留一个最长帧--深度-24
	/*(*mark_debug = "true"*)*/ output reg 			sr_rx_fifo_wren ,
	/*(*mark_debug = "true"*)*/ output reg  [ 39:0] sr_rx_fifo_wdata,
	// (*mark_debug = "true"*) input  wire [  6:0] sr_rx_fifo_cnt,
	//with CPU config
	output wire [  2:0] query_CPU_node_minmax_threshold,  //节点最小最大门限
	input  wire [ 31:0] CPU_node_minmax_threshold_data ,
	output wire [  5:0] query_CPU_queue_max_threshold  ,  //队列最大门限
	input  wire [ 31:0] CPU_queue_max_threshold_data   ,
	input  wire [ 31:0] CPU_BD_public_length           ,  //BD共享区大小
	/*(*mark_debug = "true"*)*/output reg  [ 31:0] ro_reg_np_mac_enqueue_cnt	   ,
	/*(*mark_debug = "true"*)*/output reg  [ 31:0] ro_reg_np_mac_enqueue_fail_cnt ,
	/*(*mark_debug = "true"*)*/output reg  [ 31:0] ro_reg_np_enqueue_num		   ,
	/*(*mark_debug = "true"*)*/output reg  [ 31:0] ro_reg_np_max_rx_length 	   ,
	/*(*mark_debug = "true"*)*/output reg  [ 31:0] rx_frame_cnt_node_0			   ,
	/*(*mark_debug = "true"*)*/output reg  [ 31:0] rx_frame_cnt_node_1			   ,
	/*(*mark_debug = "true"*)*/output reg  [ 31:0] rx_frame_cnt_node_2			   ,
	/*(*mark_debug = "true"*)*/output reg  [ 31:0] rx_frame_cnt_node_3			   ,
	/*(*mark_debug = "true"*)*/output reg  [ 31:0] rx_frame_cnt_node_4			   ,
	//with queue_infor_management
	output reg  		enqueue_head_infor_wr_en  ,
	output reg  [  5:0] enqueue_head_infor_wr_addr,
	output reg  [ 31:0] enqueue_head_infor_wr_data,
	//input  wire [ 31:0] enqueue_head_infor_rd_data,

	output reg  		enqueue_tail_infor_wr_en  ,
	output reg  [  5:0] enqueue_tail_infor_wr_addr,
	output reg  [ 15:0] enqueue_tail_infor_wr_data,
	input  wire [ 15:0] enqueue_tail_infor_rd_data,

	input  wire 		dequeue_tail_infor_wr_en  ,
	input  wire [  5:0] dequeue_tail_infor_wr_addr,
	input  wire [ 15:0] dequeue_tail_infor_wr_data,

	output reg  		enqueue_length_infor_wr_en  ,
	output reg  [  5:0] enqueue_length_infor_wr_addr,
	output reg  [ 15:0] enqueue_length_infor_wr_data,
	input  wire [ 15:0] enqueue_length_infor_rd_data,

    input  wire         dequeue_length_infor_wr_en  ,
    input  wire [  5:0] dequeue_length_infor_wr_addr,
    input  wire [ 15:0] dequeue_length_infor_wr_data,

	output reg  		enqueue_node_length_wr_en  ,
	output reg  [  2:0] enqueue_node_length_wr_addr,
	output reg  [ 15:0] enqueue_node_length_wr_data,
	input  wire [ 15:0] enqueue_node_length_rd_data,

    input  wire         dequeue_node_length_wr_en  ,
    input  wire [  2:0] dequeue_node_length_wr_addr,
    input  wire [ 15:0] dequeue_node_length_wr_data,

	//with mem_management
	input  wire [ 31:0] BD_public_used                   ,
	input  wire 		mem_management_init_done         ,
	output reg 			mem_allocate_request             ,
	input  wire [ 15:0] mem_allocate_address             ,
	input  wire 		mem_free_BD_fifo_empty           ,
	output reg  [  5:0]	enqueue_Linked_list_ram_wren     ,
	output reg  [ 11:0] enqueue_Linked_list_ram_waddr    ,
	output reg  [ 47:0] enqueue_Linked_list_ram_wdata    ,
	// input  wire [ 39:0] enqueue_Linked_list_ram_rdata    ,
	output reg  		enqueue_BD_public_used_update_en ,
	output reg  [ 31:0] enqueue_BD_public_used_update_num,
	//with schedule_dequeue
	output reg  		enqueue_executing_flag,
	(*mark_debug = "true"*) output reg  [  5:0] enqueue_number_reg    ,
	output reg  		queue_head_update_done,
	input  wire 		dequeue_executing_flag,
	input  wire [  5:0] dequeue_number        ,
	//with sr_rx_mul_fifo
	/*(*mark_debug = "true"*)*/ input  wire 		sr_rx_mul_fifo_full ,
	/*(*mark_debug = "true"*)*/ output reg  		sr_rx_mul_fifo_wren ,
	/*(*mark_debug = "true"*)*/ output reg  [  3:0] sr_rx_mul_fifo_wdata,
	//with enqueue_result_fifo
	/*(*mark_debug = "true"*)*/ input  wire 		enqueue_result_fifo_full,  //写数据搬移结果，不入队写0，入队写1.
	/*(*mark_debug = "true"*)*/ output reg  		enqueue_result_fifo_wren,
	/*(*mark_debug = "true"*)*/ output reg  		enqueue_result_fifo_wdata
	);

//*******************
//DEFINE PARAMETER
//*******************
//Parameter(s) 
localparam IDLE              = 8'b0000_0000;
localparam INIT              = 8'b0000_0001;
localparam READ_QUEUE_INFOR  = 8'b0000_0010;
localparam READ_INFOR_REG    = 8'b0000_0100;  //等一拍队列信息--队长、节点长用于判断门限
localparam REQUEUST_JUDGE    = 8'b0000_1000;
localparam WR_ENQUEUE_RESULT = 8'b0001_0000;
// localparam ENQUEUE_FINISH    = 8'b0010_0000;
localparam JUDGE_FAIL        = 8'b0100_0000;
//rx_fifo
// _ _ _ 4 _ _ _ _ _ _ _4 _ _ _ _ _  _ 4 _ _ _ _ _ 3 _ _ _ _ _ 11 _ _ _  _ _ _ 2 _ _ _  _ _ 4_ _ _
//|    31~28   |      27~24    |     23~20     |  19~17 |     16~6     |      5~4     |    3~0    |
//|___reserve__|___sour_port___|___dest_port___|___pri__|_frame_length_|__frame_type__|__buf_num__|
//sr_rx_fifo
// _ _ _ 4 _ _ _ _ _ _ _ 6 _ _ _ _ _ _ _ 11 _ _ _ _ _ _ 1 _ _ _ _ _ 1 _ _ _  _ _12 _ _ _  _ _ 4_ _ _
//|    39~36   |       35~30      |    29~19     |     18    |     17    |     16~4     |    3~0    |
//|___reserve__|__enqueue_number__|_frame_length_|__first_BD_|__last_BD__|__BD_address__|__buf_num__|
//Linked_list_ram--字节写入，扩充为8的整数倍
// _ _ _1_ _ _ _ _ _1_ _ _ _ _ _ _ 6 _ _ _  _ _ _ 16 _ _ _ _ _ _ 16 _ _ _
//|    40     |    39     |      38~32     |     31~16    |     15~0     |
//|__first_BD_|__last_BD__|__valid_length__|__BD_address__|_frame_length_|
//*********************
//INNER SIGNAL DECLARATION
//*********************
//REGS
//状态机
(*mark_debug = "true"*) reg [ 7:0] c_state,n_state;
(*mark_debug = "true"*) reg 		wr_enqueue_working; //正在进行上一帧申请BD工作
//队列链表信息RAM初始化完成
reg        queue_ram_init_done;
//队列号从独热码转换为十进制
reg [ 2:0] queue_number_start;
//入队门限判断
reg        judge_result,judge_result_en;
//写sr_rx_fifo延迟计数
(*mark_debug = "true"*) reg [ 1:0] wr_result_step; 
//申请到的BD数的计数，初始为BD_request_num,写一次sr_rx_fifo之后-1
(*mark_debug = "true"*) reg [ 3:0] BD_request_num_cnt;
//寄存当前帧队列--n_state = WR_QUEUE_RESULT时更新
// reg [ 5:0] enqueue_number_reg;
//rx_fifo_rdata_采样
reg [31:0] rx_fifo_rdata_sample;//采样
reg [31:0] rx_fifo_rdata_reg;//随状态机更新
reg    	   rx_fifo_empty_sample;
//寄存当前帧结点
(*mark_debug = "true"*) reg [ 2:0] enqueue_node_ID_reg;
//寄存当前帧目的端口
(*mark_debug = "true"*) reg [ 3:0] des_port_reg;
//寄存当前帧长
reg [10:0] enqueue_request_length_reg;
reg [10:0] enqueue_request_length_sub_reg;
(*mark_debug = "true"*) reg [ 3:0] BD_request_num_reg;
reg [ 3:0] buf_num_reg;
//寄存当前帧类型
reg [ 1:0] frame_type_reg;
//寄存上一帧的队列 n_state = WR_enqueue_result时更新
reg [ 5:0] previous_enqueue_number;
//BD地址采样
reg [15:0] mem_allocate_address_reg;
//寄存上一个BD地址--用于更新链表
(*mark_debug = "true"*) reg [15:0] previous_address;
//寄存申请到的第一个BD地址--用于更新队首
reg [15:0] mem_first_address;
//寄存队首数据帧所占BD数
//(*mark_debug = "true"*) reg [ 4:0] queue_head_frame_BD_num_reg;
//从帧尾写入时计数两周期
// reg [ 1:0] tail_step;

//队尾防冲突
wire [15:0] tail_infor_rd_data 				;
reg 		dequeue_tail_infor_wr_en_dl  	;
reg  [ 5:0] dequeue_tail_infor_wr_addr_dl	;
reg  [15:0] dequeue_tail_infor_wr_data_dl	;

//寄存队列信息
// reg [31:0] enqueue_head_infor_rd_data_reg    ;
reg [15:0] enqueue_tail_infor_rd_data_reg    ;

reg        dequeue_length_infor_wr_en_dl    ;
reg [ 5:0] dequeue_length_infor_wr_addr_dl  ;
reg [15:0] dequeue_length_infor_wr_data_dl  ;
reg        dequeue_node_length_wr_en_dl     ;
reg [ 2:0] dequeue_node_length_wr_addr_dl   ;
reg [15:0] dequeue_node_length_wr_data_dl   ;
//max_frame_lenth_cnt
reg  [19:0] time_1ms_cnt;
reg  [31:0] frame_length_cnt;

//WIRES
//读取得到的rx_fifo数据
wire        enqueue_fail;  //接收调度通知入队总调度入队失败--查表或者流控失败，丢弃/重定向不入队
wire [ 3:0] src_port,des_port;
wire [ 2:0] enqueue_pri;
wire [10:0] enqueue_request_length;
wire [ 1:0] frame_type;
wire [ 3:0] buf_num;
//计算得到入队数据帧申请的BD数
(*mark_debug = "true"*) wire [10:0] enqueue_request_length_sub; 
(*mark_debug = "true"*) wire [ 3:0] BD_request_num;
//入队队列号--单播/组播/广播
(*mark_debug = "true"*) wire [ 5:0] enqueue_number;
//入队节点号--单播/组播/广播
(*mark_debug = "true"*) wire [ 2:0] enqueue_node_ID;
//计算队首数据帧所占的BD数
//(*mark_debug = "true"*) wire [10:0] queue_head_frame_length_sub;
//(*mark_debug = "true"*) wire [ 4:0] queue_head_frame_BD_num;
//节点最大最小门限
wire [15:0] Node_min_threshold,Node_max_threshold;
// (*mark_debug = "true"*) wire  		last_step_of_last_BD;
//队列信息防冲突
(*mark_debug = "true"*) wire [15:0] length_infor_rd_data;
(*mark_debug = "true"*) wire [15:0] node_length_rd_data;

//*********************
//INSTANTCE MODULE
//*********************

//*********************
//MAIN CORE
//*********************
//组合逻辑提取rx_fifo
// _ _ _ 3 _ _  _ _ _ 1 _ _ _ _ _ _ _4 _ _ _ _ _  _ 4 _ _ _ _ _ 3 _ _ _ _ _ 11 _ _ _  _ _ _ 2 _ _ _  _ _ 4_ _ _
//|    31~29   |      28    |      27~24    |     23~20     |  19~17 |     16~6     |      5~4     |    3~0    |
//|___reserve__|__fail_flag_|___sour_port___|___dest_port___|___pri__|_frame_length_|__frame_type__|__buf_num__|
//独热码转换十进制
always @(*) begin
	case(des_port)
		4'b0001:queue_number_start = 3'b001;
		4'b0010:queue_number_start = 3'b010;
		4'b0100:queue_number_start = 3'b011;
		4'b1000:queue_number_start = 3'b100;
		default:queue_number_start = 3'd0;
	endcase
end

//rx_fifo_rdata采样
always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		rx_fifo_rdata_sample 			<= 32'b0 			;
		rx_fifo_empty_sample 			<= 1'b1 			;		
	end
	else begin
		rx_fifo_rdata_sample 			<= rx_fifo_rdata 			;
		rx_fifo_empty_sample 			<= rx_fifo_empty 			;		
	end
end

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		rx_fifo_rdata_reg <= 32'b0;
	end
	else if ((c_state == WR_ENQUEUE_RESULT) || (c_state == IDLE)) begin
		rx_fifo_rdata_reg <= rx_fifo_rdata_sample;
	end
	else begin
		rx_fifo_rdata_reg <= rx_fifo_rdata_reg;
	end
end
//BD_fifo采样
always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		mem_allocate_address_reg 	<= 16'b0 					;
	end
	else begin
		mem_allocate_address_reg 	<= mem_allocate_address 	;
	end
end

//队列信息采样
always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		enqueue_tail_infor_rd_data_reg 		<= 16'b0 							;
	end
	else begin
		enqueue_tail_infor_rd_data_reg  	<= enqueue_tail_infor_rd_data  		;
	end
end

//冲突检测打拍

always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		dequeue_tail_infor_wr_en_dl   	<= 1'b0  		;
    	dequeue_tail_infor_wr_addr_dl 	<= 6'b0			;
    	dequeue_tail_infor_wr_data_dl 	<= 16'b0		;
	end
	else if(enqueue_tail_infor_wr_en) begin
		dequeue_tail_infor_wr_en_dl   	<= 1'b0  		;
    	dequeue_tail_infor_wr_addr_dl 	<= 6'b0			;
    	dequeue_tail_infor_wr_data_dl 	<= 16'b0		;
	end
	else begin
	    dequeue_tail_infor_wr_en_dl   	<= dequeue_tail_infor_wr_en  		;
    	dequeue_tail_infor_wr_addr_dl 	<= dequeue_tail_infor_wr_addr		;
    	dequeue_tail_infor_wr_data_dl 	<= dequeue_tail_infor_wr_data		;
	end

end

assign tail_infor_rd_data = (((dequeue_tail_infor_wr_en) && (dequeue_tail_infor_wr_addr == enqueue_tail_infor_wr_addr))? (dequeue_tail_infor_wr_data) : 
                            (((dequeue_tail_infor_wr_en_dl) && (dequeue_tail_infor_wr_addr_dl == enqueue_number_reg))? (dequeue_tail_infor_wr_data_dl) :
                            (enqueue_tail_infor_rd_data_reg)));


always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		dequeue_length_infor_wr_en_dl   <= 1'b0 	;
		dequeue_length_infor_wr_addr_dl <= 6'b0 	;
		dequeue_length_infor_wr_data_dl <= 16'b0	;
		dequeue_node_length_wr_en_dl    <= 1'b0 	;
		dequeue_node_length_wr_addr_dl  <= 3'b0 	;
		dequeue_node_length_wr_data_dl  <= 16'b0	;
	end
	else begin
    	dequeue_length_infor_wr_en_dl   <= dequeue_length_infor_wr_en  ;
    	dequeue_length_infor_wr_addr_dl <= dequeue_length_infor_wr_addr;
    	dequeue_length_infor_wr_data_dl <= dequeue_length_infor_wr_data;
    	dequeue_node_length_wr_en_dl    <= dequeue_node_length_wr_en   ;
    	dequeue_node_length_wr_addr_dl  <= dequeue_node_length_wr_addr ;
    	dequeue_node_length_wr_data_dl  <= dequeue_node_length_wr_data ;		
	end
end

assign length_infor_rd_data = (((dequeue_length_infor_wr_en) && (dequeue_length_infor_wr_addr == enqueue_number_reg))? (dequeue_length_infor_wr_data) : 
                            (((dequeue_length_infor_wr_en_dl) && (dequeue_length_infor_wr_addr_dl == enqueue_number_reg))? (dequeue_length_infor_wr_data_dl) :
                            (enqueue_length_infor_rd_data)));
assign node_length_rd_data =(((dequeue_node_length_wr_en) && (dequeue_node_length_wr_addr == enqueue_node_ID_reg))? (dequeue_node_length_wr_data) : 
                            (((dequeue_node_length_wr_en_dl) && (dequeue_node_length_wr_addr_dl == enqueue_node_ID_reg))? (dequeue_node_length_wr_data_dl) :
                            (enqueue_node_length_rd_data)));

assign enqueue_fail           = rx_fifo_rdata_reg[28];
assign src_port               = rx_fifo_rdata_reg[27:24];
assign des_port               = rx_fifo_rdata_reg[23:20];
assign enqueue_pri            = rx_fifo_rdata_reg[19:17];
assign enqueue_request_length = rx_fifo_rdata_reg[16:6] ;
assign frame_type             = rx_fifo_rdata_reg[5:4]  ;
assign buf_num                = rx_fifo_rdata_reg[3:0]  ;
//计算入队数据帧申请的BD数
assign enqueue_request_length_sub = enqueue_request_length-11'd1;
assign BD_request_num             = enqueue_request_length_sub[10:7] + 4'd1;
//计算队列号--节点号*8+优先级-单播/24-组播、广播
assign enqueue_number  = ((frame_type == 2'b10) || (frame_type == 2'b11)) ? {3'b100,3'b000} :{(queue_number_start - 3'd1),enqueue_pri};
assign enqueue_node_ID = ((frame_type == 2'b10) || (frame_type == 2'b11)) ? 3'b100:(queue_number_start - 3'd1);
//计算队首数据帧所占BD数
//assign queue_head_frame_length_sub = enqueue_head_infor_rd_data[10:0] - 11'd1;
//assign queue_head_frame_BD_num     = queue_head_frame_length_sub[10:6] + 1'b1;
//节点最大最小门限
assign Node_min_threshold = CPU_node_minmax_threshold_data[31:16];
assign Node_max_threshold = CPU_node_minmax_threshold_data[15:0];

// assign last_step_of_last_BD = ((BD_request_num_cnt == 4'd1) && (wr_result_step == 3'd3) && wr_enqueue_working);
//三段式状态机
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		c_state <= IDLE;
	end
	else begin
		c_state <= n_state;
	end
end

always @(*) begin
	case(c_state)
		IDLE:
		begin
			if (init_done == 1'b1) begin  //预留一个最长以太网帧
				if ((rx_fifo_empty_sample == 1'b0) && (rx_fifo_empty == 1'b0) /*&& (sr_rx_fifo_cnt <= 7'd103) */&& (sr_rx_fifo_full == 1'b0) && (mem_free_BD_fifo_empty == 1'b0) && (enqueue_result_fifo_full == 1'b0)) begin
					n_state = READ_QUEUE_INFOR;
				end
				else begin
					n_state = IDLE;
				end
			end
			else begin
				n_state = INIT;
			end
		end
		INIT:
		begin
			if (init_done == 1'b1) begin
				n_state = IDLE;
			end
			else begin
				n_state = INIT;
			end
		end
		READ_QUEUE_INFOR:
		begin
			n_state = READ_INFOR_REG;
		end
		READ_INFOR_REG:  //等一拍读队长以及节点长度信息以及节点门限信息
		begin
			if (enqueue_fail == 1'b1) begin  //初步判断接收调度结果，为查表失败或者流控失败，丢弃或者重定向，入队失败写调度结果
				n_state = JUDGE_FAIL;
			end
			else begin
				n_state = REQUEUST_JUDGE;
			end
		end
		REQUEUST_JUDGE:
		begin
			if (((frame_type == 2'b10) || (frame_type == 2'b11)) && (sr_rx_mul_fifo_full == 1'b1)) begin  //多播帧，FIFO已满，入队失败
				n_state = JUDGE_FAIL;
			end
			else begin
				if ((judge_result == 1'b1) && (judge_result_en == 1'b1)) begin
					if(wr_enqueue_working) begin
						n_state = REQUEUST_JUDGE;
					end
					else begin
						n_state = WR_ENQUEUE_RESULT;
					end
				end
				else begin
					n_state = JUDGE_FAIL;
				end
			end
		end
		WR_ENQUEUE_RESULT:
		begin
			n_state = IDLE;
		end
		JUDGE_FAIL:
		begin
			n_state = IDLE;
		end
		default:
		begin
			n_state = IDLE;
		end
	endcase
end

//拉高rx_fifo读使能--首字置出FIFO，先用后读
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		rx_fifo_rden <= 1'b0;
	end
	else if (c_state == READ_QUEUE_INFOR) begin
		rx_fifo_rden <= 1'b1;
	end
	else begin
		rx_fifo_rden <= 1'b0;
	end
end

//assign rx_fifo_rden = (n_state == JUDGE_FAIL) || (n_state == WR_ENQUEUE_RESULT);

//队列链表信息RAM初始化完成
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		queue_ram_init_done <= 1'b0;
	end
	else if ((n_state == INIT) && (enqueue_Linked_list_ram_waddr == 13'd4095)) begin
		queue_ram_init_done <= 1'b1;
	end
	else begin
		queue_ram_init_done <= queue_ram_init_done;
	end
end

//初始化完成
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		init_done <= 1'b0;
	end
	else if ((queue_ram_init_done == 1'b1) && (mem_management_init_done == 1'b1)) begin
		init_done <= 1'b1;
	end
	else begin
		init_done <= init_done;
	end
end


//查询CPU门限
assign  query_CPU_node_minmax_threshold = enqueue_node_ID;
assign  query_CPU_queue_max_threshold = enqueue_number;

always @(posedge clk or negedge rst_n) begin : ENQUEUE_JUDGE
	if (~rst_n) begin
		judge_result <= 1'b0;
		judge_result_en <= 1'b0;
	end
	else if (c_state == READ_INFOR_REG) begin
		if ((enqueue_node_length_rd_data + BD_request_num) > Node_max_threshold) begin  //设置节点限制区
			judge_result    <= 1'b0;
			judge_result_en <= 1'b1;
		end
		else if (({16'b0,enqueue_length_infor_rd_data} + {16'b0,BD_request_num}) > CPU_queue_max_threshold_data) begin  //超过队列最大门限
			judge_result    <= 1'b0;
			judge_result_en <= 1'b1;
		end
		else if ((enqueue_node_length_rd_data + BD_request_num) <= Node_min_threshold) begin  //设置节点保障区
			judge_result    <= 1'b1;
			judge_result_en <= 1'b1;
		end
		else if (enqueue_node_length_rd_data > Node_min_threshold) begin  //已入队节点总长度超过节点最小保障门限，判断共享缓存区是否够用
			if (BD_public_used + BD_request_num > CPU_BD_public_length) begin  //共享缓存区溢出
				judge_result    <= 1'b0;
				judge_result_en <= 1'b1;
			end
			else begin
				judge_result    <= 1'b1;
				judge_result_en <= 1'b1;
			end
		end
		else begin  //节点已入队列长度小于最小门限，但是加上申请BD数超过最小门限
			if ((BD_public_used + enqueue_node_length_rd_data + BD_request_num - Node_min_threshold) > CPU_BD_public_length) begin
				judge_result    <= 1'b0;
				judge_result_en <= 1'b1;
			end
			else begin
				judge_result    <= 1'b1;
				judge_result_en <= 1'b1;
			end
		end
	end
	else begin
		judge_result    <= judge_result;
		judge_result_en <= judge_result_en;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		wr_enqueue_working <= 1'b0;
	end
	else if (n_state == WR_ENQUEUE_RESULT) begin
		wr_enqueue_working <= 1'b1;
	end
	else if (wr_enqueue_working && (BD_request_num_cnt == 4'b1) && (wr_result_step == 2'd3)) begin
		wr_enqueue_working <= 1'b0;
	end
	else begin
		wr_enqueue_working <= wr_enqueue_working;
	end
end
//写sr_rx_fifo延迟计数
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		wr_result_step <= 2'd0;
	end
	else if (wr_enqueue_working || (n_state == WR_ENQUEUE_RESULT)) begin
		wr_result_step <= wr_result_step + 2'd1;
	end
	else begin
		wr_result_step <= 2'd0;
	end
end

//帧信息暂存更新,n_state == WR_ENQUEUE_RESULT时不用reg其他情况使用reg
//若wire信号的扇出过大可以现在之前状态暂存一次
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		enqueue_number_reg  			<= 6'b0 	;
		enqueue_node_ID_reg 			<= 3'b0 	;
		des_port_reg 					<= 4'b0 	;
        enqueue_request_length_reg      <= 11'b0    ;
		enqueue_request_length_sub_reg  <= 11'b0 	;
		BD_request_num_reg 				<= 4'b0 	;
		buf_num_reg 					<= 4'b0 	;	
		frame_type_reg 					<= 2'b0 	;
		//queue_head_frame_BD_num_reg 	<= 5'b0 	;			
	end
	else if (n_state == WR_ENQUEUE_RESULT) begin
		enqueue_number_reg 				<= enqueue_number 				;
		enqueue_node_ID_reg 			<= enqueue_node_ID 				;
		des_port_reg 	   				<= des_port 	 				;
        enqueue_request_length_reg      <= enqueue_request_length       ;
		enqueue_request_length_sub_reg 	<= enqueue_request_length_sub 	;
		BD_request_num_reg 				<= BD_request_num 				;
		buf_num_reg 					<= buf_num 						;
		frame_type_reg 					<= frame_type 					;
		//queue_head_frame_BD_num_reg 	<= queue_head_frame_BD_num 		;
	end
	else begin
		enqueue_number_reg 				<= enqueue_number_reg 				;
		enqueue_node_ID_reg 			<= enqueue_node_ID_reg 				;
		des_port_reg 					<= des_port_reg 					;
        enqueue_request_length_reg      <= enqueue_request_length_reg       ;
		enqueue_request_length_sub_reg 	<= enqueue_request_length_sub_reg 	;
		BD_request_num_reg  			<= BD_request_num_reg 				;
		buf_num_reg 					<= buf_num_reg 						;
		frame_type_reg					<= frame_type_reg 					;
		//queue_head_frame_BD_num_reg 	<= queue_head_frame_BD_num_reg 		;
	end
end


//previous_enqueue更新
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		previous_enqueue_number <= 6'b0;
	end
	else if (n_state == WR_ENQUEUE_RESULT) begin  //最后一个BD，更新rx_fifo读使能，准备接收下一帧
		previous_enqueue_number <= enqueue_number_reg;
	end
	else if (tail_infor_rd_data == previous_address) begin
		previous_enqueue_number <= 6'b0;
	end
	else begin
		previous_enqueue_number <= previous_enqueue_number;
	end
end

//申请BD数量计数(cnt)
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		BD_request_num_cnt <= 4'd0;
	end
	else if (n_state == WR_ENQUEUE_RESULT) begin
		BD_request_num_cnt <= BD_request_num;
	end
	else if (wr_enqueue_working && (wr_result_step == 2'd3)) begin
		if (BD_request_num_cnt > 4'd1) begin
			BD_request_num_cnt <= BD_request_num_cnt - 4'd1;
		end
		else begin
			BD_request_num_cnt <= 4'd0;
		end
	end
	else begin
		BD_request_num_cnt <= BD_request_num_cnt;
	end
end

//入队正在执行标志
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		enqueue_executing_flag <= 1'b0;
	end
	else if (n_state == WR_ENQUEUE_RESULT) begin
		enqueue_executing_flag <= 1'b1;
	end
	else if (~wr_enqueue_working) begin
		enqueue_executing_flag <= 1'b0;
	end
	else begin
		enqueue_executing_flag <= enqueue_executing_flag;
	end
end

//---------暂留----------
//在哪个状态更新？
//寄存申请到的第一个BD地址
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		mem_first_address <= 16'd0;
	end
	else if (n_state == IDLE) begin
		mem_first_address <= 16'd0;
	end
	else if (n_state == WR_ENQUEUE_RESULT) begin
		mem_first_address <= mem_allocate_address_reg;
	end
	else begin
		mem_first_address <= mem_first_address;
	end
end


//更新队列信息
	//队首
	//队首信息：
	// 1、read_infor读信息-等一个read_infor_reg-judge时获得rd_data
	// 2、队首更新为当前帧第一个BD，此时未进行到下一帧的信息处理，不需要进行帧长信息的处理
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		enqueue_head_infor_wr_en   <= 1'b0;
		enqueue_head_infor_wr_addr <= 6'd0;
		enqueue_head_infor_wr_data <= 32'd0;
		queue_head_update_done     <= 1'b0;
	end
	else if (c_state == INIT) begin
		if (enqueue_head_infor_wr_addr <= 6'd63) begin
			enqueue_head_infor_wr_en   <= 1'b1;
			enqueue_head_infor_wr_addr <= enqueue_head_infor_wr_addr + 6'd1;
			enqueue_head_infor_wr_data <= 32'd0;
			queue_head_update_done     <= 1'b0;
		end
		else begin
			enqueue_head_infor_wr_en   <= 1'b0;
			enqueue_head_infor_wr_addr <= 6'd0;
			enqueue_head_infor_wr_data <= 32'd0;
			queue_head_update_done     <= 1'b0;
		end
	end
	// else if ((n_state == READ_QUEUE_INFOR) || ((n_state == READ_INFOR_REG) && wr_enqueue_working) ) begin
	else if (c_state == READ_QUEUE_INFOR) begin
		enqueue_head_infor_wr_en   <= 1'b0;
		enqueue_head_infor_wr_addr <= enqueue_number;
		enqueue_head_infor_wr_data <= 32'd0;
		queue_head_update_done     <= 1'b0;
	end
	else if (c_state == WR_ENQUEUE_RESULT) begin  //入队需要更新队首--队列为空/队列只有一帧，且入队出队操作同一队列
		// else if ((enqueue_length_infor_rd_data == {11'd0,queue_head_frame_BD_num_reg}) && (enqueue_number_reg == dequeue_number) && (dequeue_executing_flag == 1'b1)) begin  //队列只有一帧，入队出队操作同一队列
		if ((length_infor_rd_data == 16'd0) && (enqueue_number_reg == dequeue_number) && (dequeue_executing_flag == 1'b1)) begin  //队列只有一帧，入队出队操作同一队列
        	if (queue_head_update_done == 1'b0) begin
				enqueue_head_infor_wr_en   <= 1'b1;
				enqueue_head_infor_wr_addr <= enqueue_number_reg;
				enqueue_head_infor_wr_data <= {mem_allocate_address_reg,5'd0,enqueue_request_length_reg};
				queue_head_update_done     <= 1'b1;
			end
			else begin
				enqueue_head_infor_wr_en   <= 1'b0;
				enqueue_head_infor_wr_addr <= enqueue_head_infor_wr_addr;
				enqueue_head_infor_wr_data <= enqueue_head_infor_wr_data;
				queue_head_update_done     <= 1'b0;
			end
		end
        else if (length_infor_rd_data == 16'd0) begin  //队列为空
            enqueue_head_infor_wr_en   <= 1'b1;
            enqueue_head_infor_wr_addr <= enqueue_number_reg;
            enqueue_head_infor_wr_data <= {mem_allocate_address_reg,5'd0,enqueue_request_length_reg};
            queue_head_update_done     <= 1'b0;
        end
		else begin
			enqueue_head_infor_wr_en   <= 1'b0;
			enqueue_head_infor_wr_addr <= enqueue_head_infor_wr_addr;
			enqueue_head_infor_wr_data <= enqueue_head_infor_wr_data;
			queue_head_update_done     <= 1'b0;
		end
	end
	else begin
		enqueue_head_infor_wr_en   <= 1'b0;
		enqueue_head_infor_wr_addr <= enqueue_head_infor_wr_addr;
		enqueue_head_infor_wr_data <= enqueue_head_infor_wr_data;
		queue_head_update_done     <= 1'b0;
	end
end


	//队尾
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		enqueue_tail_infor_wr_en   		<= 1'b0;
		enqueue_tail_infor_wr_addr 		<= 6'd0;
		enqueue_tail_infor_wr_data 		<= 16'd0;
	end
	else if (c_state == INIT) begin
		if (enqueue_tail_infor_wr_addr <= 6'd63) begin
			enqueue_tail_infor_wr_en   		<= 1'b1;
			enqueue_tail_infor_wr_addr 		<= enqueue_tail_infor_wr_addr + 6'd1;
			enqueue_tail_infor_wr_data 		<= 16'd0;
		end
		else begin
			enqueue_tail_infor_wr_en   		<= 1'b0;
			enqueue_tail_infor_wr_addr 		<= 5'd0;
			enqueue_tail_infor_wr_data 		<= 16'd0;
		end
	end
	else if (n_state == READ_QUEUE_INFOR) begin
		enqueue_tail_infor_wr_en   		<= 1'b0;
		enqueue_tail_infor_wr_addr 		<= enqueue_number;
		enqueue_tail_infor_wr_data 		<= 16'd0;
	end
	else if ((BD_request_num_reg == 4'b1) && (c_state == WR_ENQUEUE_RESULT)) begin //最短帧入队
		enqueue_tail_infor_wr_en   		<= 1'b1;
		enqueue_tail_infor_wr_addr 		<= enqueue_number_reg;
		enqueue_tail_infor_wr_data 		<= mem_allocate_address_reg;
	end
	else if ((wr_enqueue_working) && (BD_request_num_cnt == 4'd1) && (BD_request_num_reg != 4'd1)) begin  //队尾只需要在入队最后一个BD时，修改队尾为当前申请的空闲BD地址
		if ((wr_result_step == 2'd0) && (n_state != READ_QUEUE_INFOR)) begin
			enqueue_tail_infor_wr_en   		<= 1'b1;
			enqueue_tail_infor_wr_addr 		<= enqueue_number_reg;
			enqueue_tail_infor_wr_data 		<= mem_allocate_address_reg;
		end
		else if ((wr_result_step == 2'd1) && (n_state == READ_INFOR_REG)) begin //当更新与读取冲突时延迟一个钟更新
			enqueue_tail_infor_wr_en   		<= 1'b1;
			enqueue_tail_infor_wr_addr 		<= enqueue_number_reg;
			enqueue_tail_infor_wr_data 		<= mem_allocate_address_reg;
		end
		else begin
			enqueue_tail_infor_wr_en   		<= 1'b0;
			enqueue_tail_infor_wr_addr 		<= enqueue_number;
			enqueue_tail_infor_wr_data 		<= 16'd0;
		end
	end
	else begin
		enqueue_tail_infor_wr_en   		<= 1'b0;
		enqueue_tail_infor_wr_addr 		<= enqueue_number;
		enqueue_tail_infor_wr_data 		<= 16'd0;
	end
end

	//队长
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		enqueue_length_infor_wr_en   <= 1'b0;
		enqueue_length_infor_wr_addr <= 6'd0;
		enqueue_length_infor_wr_data <= 16'd0;
	end
	else if (c_state == INIT) begin
		if (enqueue_length_infor_wr_addr <= 6'd63) begin
			enqueue_length_infor_wr_en   <= 1'b1;
			enqueue_length_infor_wr_addr <= enqueue_length_infor_wr_addr + 6'd1;
			enqueue_length_infor_wr_data <= 16'd0; 
		end
		else begin
			enqueue_length_infor_wr_en   <= 1'b0;
			enqueue_length_infor_wr_addr <= 6'd0;
			enqueue_length_infor_wr_data <= 16'd0;
		end
	end
	else if (n_state == READ_QUEUE_INFOR) begin
		enqueue_length_infor_wr_en   <= 1'b0;
		enqueue_length_infor_wr_addr <= enqueue_number;
		enqueue_length_infor_wr_data <= 16'd0;
	end
	else if (c_state == WR_ENQUEUE_RESULT) begin
        enqueue_length_infor_wr_en   <= 1'b1;
        enqueue_length_infor_wr_addr <= enqueue_number_reg;
        enqueue_length_infor_wr_data <= length_infor_rd_data + BD_request_num_reg;
	end 
	else begin
		enqueue_length_infor_wr_en   <= 1'b0;
		enqueue_length_infor_wr_addr <= enqueue_number;
		enqueue_length_infor_wr_data <= enqueue_length_infor_wr_data;
	end
end

	//节点长
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		enqueue_node_length_wr_en   <= 1'd0;
		enqueue_node_length_wr_addr <= 3'd0;
		enqueue_node_length_wr_data <= 16'd0;
	end
	else if (c_state == INIT) begin
		if (enqueue_node_length_wr_addr <= 3'd7) begin
			enqueue_node_length_wr_en   <= 1'b1;
			enqueue_node_length_wr_addr <= enqueue_node_length_wr_addr + 3'd1;
			enqueue_node_length_wr_data <= 16'd0;
		end
		else begin
			enqueue_node_length_wr_en   <= 1'd0;
			enqueue_node_length_wr_addr <= 2'd0;
			enqueue_node_length_wr_data <= 16'd0;
		end
	end
	else if (n_state == READ_QUEUE_INFOR) begin
		enqueue_node_length_wr_en   <= 1'd0;
		enqueue_node_length_wr_addr <= enqueue_node_ID;
		enqueue_node_length_wr_data <= 16'd0;
	end
    else if (c_state == WR_ENQUEUE_RESULT) begin
         enqueue_node_length_wr_en   <= 1'b1;
         enqueue_node_length_wr_addr <= enqueue_node_ID_reg;
         enqueue_node_length_wr_data <= node_length_rd_data + BD_request_num_reg;
    end
	else begin
		enqueue_node_length_wr_en   <= 1'd0;
		enqueue_node_length_wr_addr <= enqueue_node_ID;
		enqueue_node_length_wr_data <= 16'd0;
	end
end

// 缓存申请
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		mem_allocate_request <= 1'b0;
	end
	else if (( wr_enqueue_working) && (wr_result_step == 2'd1)) begin
		mem_allocate_request <= 1'b1;
	end
	else begin
		mem_allocate_request <= 1'b0;
	end
end

//寄存上一个BD地址信息
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		previous_address <= 16'd0;
	end
	else if (wr_enqueue_working && (wr_result_step == 2'd3)) begin
		previous_address <= mem_allocate_address_reg;
	end
	else begin
		previous_address <= previous_address;
	end
end

//Linked_list_ram--字节写入，扩充为8的整数倍
// _ _ _1_ _ _ _ _ _1_ _ _ _ _ _ _ 6 _ _ _  _ _ _ 12 _ _ _ _ _ _ 11 _ _ _
//|    40     |    39     |      38~32     |     31~16    |     15~0     |
//|__fisrt_BD_|__last_BD__|__valid_length__|__BD_address__|_frame_length_|

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		enqueue_Linked_list_ram_wren  <= 6'd0;
		enqueue_Linked_list_ram_waddr <= 12'd0;
		enqueue_Linked_list_ram_wdata <= 41'd0;
	end
	else if (n_state == INIT) begin
		if (enqueue_Linked_list_ram_waddr <= 12'd4095) begin
			enqueue_Linked_list_ram_wren  <= 6'b111111;
			enqueue_Linked_list_ram_waddr <= enqueue_Linked_list_ram_waddr + 12'd1;
			enqueue_Linked_list_ram_wdata <= 41'd0;
		end
		else begin
			enqueue_Linked_list_ram_wren  <= 6'd0;
			enqueue_Linked_list_ram_waddr <= 12'd0;
			enqueue_Linked_list_ram_wdata <= 40'd0;
		end
	end
	else if ((wr_enqueue_working || (n_state == WR_ENQUEUE_RESULT)) && (wr_result_step == 2'd0)) begin  //写当前分配BD信息
		if ((BD_request_num == 4'd1) && (n_state == WR_ENQUEUE_RESULT)) begin  //最短帧只有一个BD
			enqueue_Linked_list_ram_wren  <= 6'b111111;
			enqueue_Linked_list_ram_waddr <= mem_allocate_address_reg[11:0];
			enqueue_Linked_list_ram_wdata <= {7'b0,1'b1,1'b1,enqueue_request_length_sub[6:0],16'd0,16'd0};
		end
		else if (n_state == WR_ENQUEUE_RESULT) begin  //非最短帧首BD
			enqueue_Linked_list_ram_wren  <= 6'b111111;
			enqueue_Linked_list_ram_waddr <= mem_allocate_address_reg[11:0];
			enqueue_Linked_list_ram_wdata <= {7'b0,1'b1,1'b0,7'd127,16'd0,16'd0};
		end
		else if (BD_request_num_cnt == 4'd1) begin  //非最短帧尾BD
			enqueue_Linked_list_ram_wren  <= 6'b111111;
			enqueue_Linked_list_ram_waddr <= mem_allocate_address_reg[11:0];
			enqueue_Linked_list_ram_wdata <= {7'b0,1'b0,1'b1,enqueue_request_length_sub_reg[6:0],16'd0,16'd0};
		end
		else begin
			enqueue_Linked_list_ram_wren  <= 6'b111111;
			enqueue_Linked_list_ram_waddr <= mem_allocate_address_reg[11:0];
			enqueue_Linked_list_ram_wdata <= {7'd0,1'b0,1'b0,7'd127,16'd0,16'd0};
		end
	end	
	else if (wr_enqueue_working && (wr_result_step == 2'd1)) begin  //写上一个BD信息(若上一帧与这一帧队列相同时直接用previous_address)
		if (BD_request_num_cnt == BD_request_num_reg) begin  //当前为首BD，需要修改上一帧尾BD的下一跳地址，下一跳帧长
			if ((enqueue_number_reg == previous_enqueue_number) /*&& (tail_step != 2'b0)*/) begin  //
				enqueue_Linked_list_ram_wren  <= 6'b001111;
				enqueue_Linked_list_ram_waddr <= previous_address[11:0];
				enqueue_Linked_list_ram_wdata <= {16'd0,mem_allocate_address_reg,5'd0,enqueue_request_length_reg};
			end
			else if (tail_infor_rd_data == 16'd0) begin  //尾指针为0，说明该帧为首BD
				enqueue_Linked_list_ram_wren  <= 6'd0;
				enqueue_Linked_list_ram_waddr <= 12'd0;
				enqueue_Linked_list_ram_wdata <= 48'd0;
			end
			else begin
				enqueue_Linked_list_ram_wren  <= 6'b001111;
				enqueue_Linked_list_ram_waddr <= enqueue_tail_infor_rd_data_reg[11:0];
				enqueue_Linked_list_ram_wdata <= {16'd0,mem_allocate_address_reg,5'd0,enqueue_request_length_reg};
			end
		end
		else begin  //帧内BD，修改上一BD的下一跳
			enqueue_Linked_list_ram_wren  <= 6'b001100;
			enqueue_Linked_list_ram_waddr <= previous_address[11:0];
			enqueue_Linked_list_ram_wdata <= {16'd0,mem_allocate_address,16'd0};
		end
	end
	else begin
		enqueue_Linked_list_ram_wren  <= 6'd0;
		enqueue_Linked_list_ram_waddr <= 12'd0;
		enqueue_Linked_list_ram_wdata <= 48'd0;
	end
end

//更新共享缓存区
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		enqueue_BD_public_used_update_num <= 32'd0;
		enqueue_BD_public_used_update_en  <= 1'b0;
	end
	else if (c_state == WR_ENQUEUE_RESULT) begin
		if (node_length_rd_data > Node_max_threshold) begin  //节点队长大于最小门限，申请的BD都是共享缓存BD
			enqueue_BD_public_used_update_num <= BD_request_num_reg;
			enqueue_BD_public_used_update_en  <= 1'b1;
		end
		else if ((node_length_rd_data + BD_request_num_reg) > Node_max_threshold) begin  //节点队长小于最小门限，但是节点队长+申请BD>节点最小门限，申请部分共享缓存BD
			enqueue_BD_public_used_update_num <= node_length_rd_data + BD_request_num_reg - Node_max_threshold;
			enqueue_BD_public_used_update_en  <= 1'b1;
		end
		else begin
			enqueue_BD_public_used_update_num <= 32'd0;
			enqueue_BD_public_used_update_en  <= 1'b0;
		end
	end
	else begin
		enqueue_BD_public_used_update_num <= 32'd0;
		enqueue_BD_public_used_update_en  <= 1'b0;
	end
end

//写sr_rx_fifo
// _ _ _ 4 _ _ _ _ _ _ _ 6 _ _ _ _ _ _ _ 11 _ _ _ _ _ _ 1 _ _ _ _ _ 1 _ _ _  _ _13 _ _ _  _ _ 4_ _ _
//|    39~36   |       35~30      |    29~19     |     18    |     17    |     16~4     |    3~0    |
//|___reserve__|__enqueue_number__|_frame_length_|__first_BD_|__last_BD__|__BD_address__|__buf_num__|
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		sr_rx_fifo_wdata <= 40'd0;
		sr_rx_fifo_wren  <= 1'b0;
	end
	// else if (n_state == JUDGE_FAIL) begin  //入队失败也要写一个结果，供接收总线从分组处理FIFO中的读出数据帧--入队失败不写了，有一个入队结果FIFO
	// 	sr_rx_fifo_wdata <= {6'd1,5'd0,enqueue_request_length,18'd0};
	// 	sr_rx_fifo_wren  <= 1'b1;
	// end
	else if ((wr_enqueue_working) && (wr_result_step == 1'b1)) begin
		sr_rx_fifo_wren <= 1'b1;
		if (BD_request_num_reg == 4'd1) begin  //最短帧，只有一个BD
			sr_rx_fifo_wdata <= {
								4'd0,
								enqueue_number_reg,
								enqueue_request_length_sub_reg,
								1'b1,
								1'b1,
								mem_allocate_address_reg[12:0],
								buf_num_reg
								};
		end
		else if (c_state == WR_ENQUEUE_RESULT) begin  //非最短帧，首BD
			sr_rx_fifo_wdata <= {
								4'd0,
								enqueue_number_reg,
								enqueue_request_length_sub_reg,
								1'b1,
								1'b0,
								mem_allocate_address_reg[12:0],
								buf_num_reg
								};
		end
		else if (BD_request_num_cnt == 4'd1) begin  //非最短帧，尾BD
			sr_rx_fifo_wdata <= {
								4'd0,
								enqueue_number_reg,
								enqueue_request_length_sub_reg,
								1'b0,
								1'b1,
								mem_allocate_address_reg[12:0],
								buf_num_reg
								};
		end
		else  begin  //帧中间部分
			sr_rx_fifo_wdata <= {
								4'd0,
								enqueue_number_reg,
								enqueue_request_length_sub_reg,
								1'b0,
								1'b0,
								mem_allocate_address_reg[12:0],
								buf_num_reg
								};
		end
	end
	else begin
		sr_rx_fifo_wdata <= 40'd0;
		sr_rx_fifo_wren  <= 1'b0;
	end
end


//多播帧，写发送端口列表
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		sr_rx_mul_fifo_wren  <= 1'b0;
		sr_rx_mul_fifo_wdata <= 4'd0;
	end
	else if ((c_state == WR_ENQUEUE_RESULT) && ((frame_type_reg == 2'b10) || (frame_type_reg == 2'b11))) begin
		sr_rx_mul_fifo_wren  <= 1'b1;
		sr_rx_mul_fifo_wdata <= des_port;
	end
	else begin
		sr_rx_mul_fifo_wren  <= 1'b0;
		sr_rx_mul_fifo_wdata <= 4'd0;
	end
end

//写入队结果
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		enqueue_result_fifo_wren  <= 1'b0;
		enqueue_result_fifo_wdata <= 1'b0;
	end
	else if (n_state == JUDGE_FAIL) begin
		enqueue_result_fifo_wren  <= 1'b1;
		enqueue_result_fifo_wdata <= 1'b0;
	end
	else if (c_state == WR_ENQUEUE_RESULT) begin
		enqueue_result_fifo_wren  <= 1'b1;
		enqueue_result_fifo_wdata <= 1'b1;
	end
	else begin
		enqueue_result_fifo_wren  <= 1'b0;
		enqueue_result_fifo_wdata <= 1'b0;
	end
end

//mem_req_cnt

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		ro_reg_np_mac_enqueue_cnt <= 32'd0;
	end
	else if (enqueue_result_fifo_wren) begin
		ro_reg_np_mac_enqueue_cnt <= ro_reg_np_mac_enqueue_cnt + 32'b1;
	end
	else begin
		ro_reg_np_mac_enqueue_cnt <= ro_reg_np_mac_enqueue_cnt;
	end
end

//fail to request memory
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		ro_reg_np_mac_enqueue_fail_cnt <= 32'd0;
	end
	else if (enqueue_result_fifo_wren && (!enqueue_result_fifo_wdata)) begin
		ro_reg_np_mac_enqueue_fail_cnt <= ro_reg_np_mac_enqueue_fail_cnt + 32'b1;
	end
	else begin
		ro_reg_np_mac_enqueue_fail_cnt <= ro_reg_np_mac_enqueue_fail_cnt;
	end
end

//mem_req_success
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		ro_reg_np_enqueue_num <= 32'd0;
	end
	else if (enqueue_result_fifo_wren && enqueue_result_fifo_wdata) begin
		ro_reg_np_enqueue_num <= ro_reg_np_enqueue_num + 32'b1;
	end
	else begin
		ro_reg_np_enqueue_num <= ro_reg_np_enqueue_num;
	end
end

// max_dequeue_length_cnt
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		time_1ms_cnt <= `ONE_MS;
	end
	else if (|time_1ms_cnt) begin
		time_1ms_cnt <= time_1ms_cnt - 20'b1;
	end
	else begin
		time_1ms_cnt <= `ONE_MS;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		frame_length_cnt <= 32'b0;
	end
	else if (~(|time_1ms_cnt) && (c_state == WR_ENQUEUE_RESULT)) begin
		frame_length_cnt <= {18'b0,enqueue_request_length_reg + 11'd24,3'b0};
	end
	else if(~(|time_1ms_cnt)) begin
		frame_length_cnt <= 32'b0;
	end
	else if (c_state == WR_ENQUEUE_RESULT) begin
		frame_length_cnt <= frame_length_cnt + {18'b0,enqueue_request_length_reg + 11'd24,3'b0};
	end
	else begin
		frame_length_cnt <= frame_length_cnt;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		ro_reg_np_max_rx_length <= 32'b0;
	end
	else if (~(|time_1ms_cnt)) begin
		ro_reg_np_max_rx_length <= /*((frame_length_cnt > ro_reg_np_max_rx_length)?*/ frame_length_cnt /*: ro_reg_np_max_rx_length)*/;
	end
	else begin
		ro_reg_np_max_rx_length <= ro_reg_np_max_rx_length;
	end
end

//count rx frame for cpu
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		rx_frame_cnt_node_0  <= 32'b0;
	end
	else if ((c_state == WR_ENQUEUE_RESULT) && enqueue_node_ID_reg == 3'd0) begin
		rx_frame_cnt_node_0  <= rx_frame_cnt_node_0 + 32'b1;
	end
	else begin
		rx_frame_cnt_node_0  <= rx_frame_cnt_node_0;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		rx_frame_cnt_node_1  <= 32'b0;
	end
	else if ((c_state == WR_ENQUEUE_RESULT) && enqueue_node_ID_reg == 3'd1) begin
		rx_frame_cnt_node_1  <= rx_frame_cnt_node_1 + 32'b1;
	end
	else begin
		rx_frame_cnt_node_1  <= rx_frame_cnt_node_1;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		rx_frame_cnt_node_2  <= 32'b0;
	end
	else if ((c_state == WR_ENQUEUE_RESULT) && enqueue_node_ID_reg == 3'd2) begin
		rx_frame_cnt_node_2  <= rx_frame_cnt_node_2 + 32'b1;
	end
	else begin
		rx_frame_cnt_node_2  <= rx_frame_cnt_node_2;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		rx_frame_cnt_node_3  <= 32'b0;
	end
	else if ((c_state == WR_ENQUEUE_RESULT) && enqueue_node_ID_reg == 3'd3) begin
		rx_frame_cnt_node_3  <= rx_frame_cnt_node_3 + 32'b1;
	end
	else begin
		rx_frame_cnt_node_3  <= rx_frame_cnt_node_3;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		rx_frame_cnt_node_4  <= 32'b0;
	end
	else if ((c_state == WR_ENQUEUE_RESULT) && enqueue_node_ID_reg == 3'd4) begin
		rx_frame_cnt_node_4  <= rx_frame_cnt_node_4 + 32'b1;
	end
	else begin
		rx_frame_cnt_node_4  <= rx_frame_cnt_node_4;
	end
end

// `ifdef SIM
// //****************************打印队列信息************************************//
// integer enqueue_BD;
// initial
// begin
// 	enqueue_BD = $fopen("enqueue_BD.txt");
// end

// always @(posedge clk) begin
// 	if (sr_rx_fifo_wren) begin
// 		$fwrite(enqueue_BD,"FIRST_FLAG:%d--BD:%d--LAST_FLAG:%d\n",sr_rx_fifo_wdata[18],sr_rx_fifo_wdata[16:4],sr_rx_fifo_wdata[17]);
// 	end
// end

// initial
// begin
// 	wait(enqueue_cnt == `SEND_NUM && c_state == IDLE)
// 		$fclose(enqueue_BD);
// end
// `endif

endmodule
